package cn.assumejson.springframework.beans.context.support;

import cn.assumejson.springframework.beans.context.ApplicationContext;
import cn.assumejson.springframework.beans.factory.BeansException;
import cn.assumejson.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import cn.assumejson.springframework.beans.factory.support.DefaultListableBeanFactory;
import cn.hutool.core.lang.Assert;

/**
 * 获取Bean工厂并且加载资源
 *
 * @author Mr. Li
 * @version 1.0
 * @since 1.0 2021/11/30 15:38
 */
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {

    private String[] configLocations;

    private DefaultListableBeanFactory beanFactory;

    private final Object beanFactoryMonitor = new Object();

    public AbstractRefreshableApplicationContext(ApplicationContext parent) {
        super(parent);
    }

    @Override
    protected void refreshBeanFactory() throws BeansException {
        // Obtain beanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();

        // 加载BeanDefinition
        loadBeanDefinitions(beanFactory);

        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }

    @Override
    public ConfigurableListableBeanFactory getBeanFactory() {
        synchronized (this.beanFactoryMonitor) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("BeanFactory not initialized or already closed - " +
                        "call 'refresh' before accessing beans via the ApplicationContext");
            }
            return this.beanFactory;
        }
    }

    

    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory);

    private DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory();
    }

    public void setConfigLocation(String location) {
        setConfigLocations(location);
    }

    public void setConfigLocations(String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {
                this.configLocations[i] = locations[i];
            }
        } else {
            this.configLocations = null;
        }
    }


    protected String[] getConfigLocations() {
        return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
    }

    protected String[] getDefaultConfigLocations() {
        return null;
    }
}
